﻿namespace Core.Frame
{
    public class ControlDefine
    {
        public static int LogicFrameRate = 10;
        public const int ClientFrameRate = 60;
    }

    public enum GlobalEventType
    {
        //收到该事件的时候，我们应该去处理玩家的一些操作指令，更新刀各位加对应的数据层中
        LogicFrameUpdate,

        //根据当前玩家的数据，执行响应的数据更新，逻辑处理。如玩家碰撞到什么，移动到哪里等等，这些多是在数据层的更新
        ClientFrameUpdate,

        //同样根据当前玩家的数据，如玩家的位置坐标，去刷新画面明显是玩家的位置变化
        ClientShowFrameUpdate,
    }

    public class GlobalEvent
    {
        public static void Dispatch(GlobalEventType type, int frame)
        {

        }

        public static void Dispatch(GlobalEventType type, float deltaTime)
        {

        }
    }

    public class DataManager
    {
        public class GameFrameData
        {
            public int LastSyncFrame;
        }

        public static GameFrameData Data;
    }


    public class FrameManager1
    {
        //ControlDefine.CLIENT_FRAME_RATE客户端的客户端帧数FPS，如 30，60帧
        public static readonly float ClientFrameTime = 1.0f / ControlDefine.ClientFrameRate;

        //当前逻辑帧（第几帧）
        public int CurrLogicFrame { get; private set; }

        //逻辑帧数FPS，如10帧，能满足大部分游戏的操作需求
        public int FrameRate { get; private set; }

        //当前客户端帧（第几帧）
        public int ClientFrameNum { get; private set; }

        //客户端帧数与逻辑帧数的倍率
        public float ClientServerFrameRate { get; private set; }

        private float startTime = 0;

        public FrameManager1(int frameRate)
        {
            FrameRate = frameRate;

            //clientServerFrameRate应该要是整数
            ClientServerFrameRate = ControlDefine.ClientFrameRate / frameRate;
        }

        public void Restart()
        {
            ClientFrameNum = 0;
            startTime = 0;
            CurrLogicFrame = 0;
        }

        //逻辑帧的更新，受服务器接收数据的驱动
        public void LogicUpdate()
        {
            //客户单已接收到的最新的帧
            var lastSyncFrame = DataManager.Data.LastSyncFrame;
            //已接受到当前帧的输入时可以进行当前帧的逻辑并继续向下推进逻辑帧
            if (lastSyncFrame > CurrLogicFrame)
            {
                if (lastSyncFrame > CurrLogicFrame + 1)
                {
                    //快进帧，发现客户端正在运行的逻辑帧落后服务器接收到的逻辑帧，则客户端快速跟进到最新
                    StepToLogicFrame(lastSyncFrame);
                }
                else
                {
                    //保持正常速率处理帧数据
                    //cc.director.getScheduler().setTimeScale(1);
                }
            }
        }

        private void StepToLogicFrame(int frame)
        {
            while (ClientFrameNum < ClientServerFrameRate * frame)
            {
                UpdateClient(ClientFrameTime, false);
            }
            UpdateClient(ClientFrameTime, false);
        }


        public float UpdateTime = 0;
        public float UpdateCount = 0;
        public void Update(float dt)
        {
            LogicUpdate();
            UpdateClient(dt, true);
        }


        //更新客户端帧，主要是当前逻辑帧下，客户端帧的处理
        //isUpdateShowFrame，是否需要更新玩具的可视层
        private void UpdateClient(float dt, bool isUpdateShowFrame = true)
        {
            var lastSyncFrame = DataManager.Data.LastSyncFrame;

            if (ClientServerFrameRate * lastSyncFrame > 0 && isUpdateShowFrame)
            {
                GlobalEvent.Dispatch(GlobalEventType.ClientShowFrameUpdate, dt);
            }

            //客户端帧过快，服务器帧有延迟
            if (ClientFrameNum > ClientServerFrameRate * lastSyncFrame)
            {
                return;
            }

            while (startTime >= ClientFrameTime && ClientFrameNum <= ClientServerFrameRate * lastSyncFrame)
            {
                if (lastSyncFrame >= CurrLogicFrame
                    && ClientFrameNum == CurrLogicFrame * ClientServerFrameRate)
                {
                    GlobalEvent.Dispatch(GlobalEventType.LogicFrameUpdate, CurrLogicFrame);
                    CurrLogicFrame++;
                }
                if (ClientFrameNum < ClientServerFrameRate * lastSyncFrame)
                {
                    ++ClientFrameNum;
                    GlobalEvent.Dispatch(GlobalEventType.ClientFrameUpdate, ClientFrameNum);
                    startTime -= ClientFrameTime;
                }
                else
                {
                    break;
                }
            }
        }
    }

}
